package com.derbysoft.synxisadapter.dswitch2.service.impl;

import com.derbysoft.remote.dswitch.core.GenericRQ;
import com.derbysoft.remote.dswitch.core.GenericRS;
import com.derbysoft.remote.dswitch.core.ResponseHeader;
import com.derbysoft.remote.dswitch.core.SuccessDTO;
import com.derbysoft.remote.dswitch.generic.constants.TransactionStatusType;
import com.derbysoft.remote.dswitch.generic.constants.UniqueIDType;
import com.derbysoft.remote.dswitch.generic.dto.SimpleAmountDTO;
import com.derbysoft.remote.dswitch.generic.dto.UniqueIDDTO;
import com.derbysoft.remote.dswitch.hotel.dto.*;
import com.derbysoft.remote.share.Currency;
import com.derbysoft.synxisadapter.commons.model.Hotel;
import com.derbysoft.synxisadapter.commons.model.Reservation;
import com.derbysoft.synxisadapter.dswitch2.translator.impl.AbstractRQTranslator;

import java.math.BigDecimal;

public class HotelPreviewServiceImpl extends AbstractReservationService {

    @Override
    public GenericRS<HotelReservationRS> invoke(GenericRQ<HotelReservationRQ> rq) {
        String ersp = saveReservation(rq.getPayload());
        GenericRS<HotelAvailRS> availRS = getAvailRS(rq);
        if (availRS.hasErrors()) {
            updateStatus(ersp, Reservation.Status.PREVIEW_FAILED);
            return availErrorRS(rq, availRS);
        } else {
            updateStatus(ersp, Reservation.Status.PREVIEW);
            return availSuccessRS(rq, availRS);
        }
    }

    private GenericRS<HotelReservationRS> availSuccessRS(GenericRQ<HotelReservationRQ> rq, GenericRS<HotelAvailRS> availRS) {
        HotelReservationDTO reservation = rq.getPayload().getHotelReservation();
        TotalDTO total = calcTotal(availRS, reservation.getRoomStays().get(0));
        if (total == null) {
            return noAllotmentRS(rq);
        } else {
            total.setTaxes(createTaxes(availRS.getPayload().getHotelAvailRoomStay().getRoomStays(), rq));
            reservation.getRoomStays().get(0).setTotal(total);
            return previewRS(rq, reservation, availRS.getPayload());
        }
    }

    protected TotalDTO calcTotal(GenericRS<HotelAvailRS> availRS, ReservationRoomStayDTO reservationRoomStayDTO) {
        RoomStayCandidateDTO candidate = createRoomStayCandidate(reservationRoomStayDTO);
        for (AvailRoomStayDTO availRoomStayDTO : availRS.getPayload().getHotelAvailRoomStay().getRoomStays()) {
            if (availRoomStayDTO.getRoomType().getCode().equals(reservationRoomStayDTO.getRoomTypeCode()) &&
                    availRoomStayDTO.getRatePlan().getCode().equals(reservationRoomStayDTO.getRatePlanCode())) {
                return innerCalcTotal(reservationRoomStayDTO, candidate, availRoomStayDTO);
            }
        }
        return null;
    }

    private TotalDTO innerCalcTotal(ReservationRoomStayDTO reservationRoomStayDTO, RoomStayCandidateDTO candidate,
                                    AvailRoomStayDTO availRoomStayDTO) {
        TotalDTO total = new TotalDTO();
        total.setAdditionalCharge(availRoomStayDTO.getTotalAdditionalCharge(candidate, reservationRoomStayDTO.getStayDateRange()));
        total.setServiceCharge(availRoomStayDTO.getTotalServiceCharge(candidate, reservationRoomStayDTO.getStayDateRange()));

        BigDecimal pureRate = BigDecimal.ZERO;
        BigDecimal includedTaxAndFeeRate = BigDecimal.ZERO;

        for (RateDTO rateDTO : availRoomStayDTO.getRoomRate().getRates()) {
            String[] rateValues = rateDTO.getTpaExtensions().getElement(AbstractRQTranslator.RATE_RULE).split("\\|");
            pureRate = pureRate.add(new BigDecimal(rateValues[0]));
            includedTaxAndFeeRate = includedTaxAndFeeRate.add(new BigDecimal(rateValues[3]));
        }

        Currency currency = availRoomStayDTO.getRoomRate().getRates().get(0).getPureAmount().getCurrency();
        SimpleAmountDTO pureAmount = new SimpleAmountDTO(pureRate, currency);
        total.setPureAmount(pureAmount);
        SimpleAmountDTO totalAmount = new SimpleAmountDTO(includedTaxAndFeeRate, pureAmount.getCurrency());
        total.setTotalAmount(totalAmount);
        total.setTax(new SimpleAmountDTO(includedTaxAndFeeRate.subtract(pureRate),
                currency));
        return total;
    }

    private GenericRS<HotelReservationRS> previewRS(GenericRQ<HotelReservationRQ> rq, HotelReservationDTO reservation, HotelAvailRS hotelAvailRS) {
        GenericRS<HotelReservationRS> rs = new GenericRS<HotelReservationRS>();
        rs.setSuccess(new SuccessDTO());
        rs.setHeader(new ResponseHeader(rq.getHeader().getTaskId()));
        HotelReservationRS reservationRS = new HotelReservationRS();
        reservationRS.setHotelReservation(reservation);
        reservationRS.setHotelReservationIDs(rq.getPayload().getHotelReservationIDs());
        reservationRS.setOriginalBuyer(rq.getPayload().getOriginalBuyer());
        Hotel hotel = hotelRepository.findByPassport(rq.getPayload().getHotelReservation().getHotelRef().getCode(), Hotel.Status.ENABLED);
        reservationRS.setOriginalProvider(new UniqueIDDTO(hotel.getProviderPassport(), UniqueIDType.GROUP));
        reservationRS.setTotal(reservation.getRoomStays().get(0).getTotal());
        reservationRS.setResStatusType(TransactionStatusType.INITIATED);
        reservationRS.setCancelPolicy(findCancelPolicy(hotelAvailRS, reservation));
        reservationRS.getHotelReservation().getRoomStays().get(0).setRoomRate(findRoomRate(hotelAvailRS, reservation));
        rs.setPayload(reservationRS);
        return rs;
    }
}
